//
// GPSMapEdit
// (c) Konstantin Galichsky (kg@geopainting.com), 2002-2007
//
// 'Transform' tool.
//

# include "StdAfx.h"
# include "TransformDefFile.h"
# include "PtAlgo.h"
# include "FileWriter.h"
# include "ParseHelpers.h"
# include "Wrappers.h"
# include "Globals.h"

static const char c_strTrdSignature_Old [] = "GPSMap Edit Transformation Data 1.0\r\n";
const size_t c_cTrdSignatureSize_Old = sizeof (c_strTrdSignature_Old) - 1;
static const char c_strTrdSignature     [] = "GPSMapEdit Transformation Data 1.0\r\n";
const size_t c_cTrdSignatureSize = sizeof (c_strTrdSignature) - 1;

bool SaveTransformDefFile (const ptpairs_t & _PtPairs) {
	// Prepare default file name.
	char strFileName [MAX_PATH + 1];
	::strncpy (strFileName, g_strFileName, MAX_PATH);
	strFileName [MAX_PATH] = '\0';
	if (strFileName [0]) {
		char * pExt = ::strrchr (strFileName, '.');
		if (pExt)
			::strcpy (pExt, ".trd");
		else
			::strcat (strFileName, ".trd");
	}

	// Ask file name.
	OPENFILENAME ofn;
	::ZeroMemory (& ofn, sizeof (OPENFILENAME));
	ofn.lStructSize  = sizeof (OPENFILENAME);
	ofn.hwndOwner    = g_hWnd;
	ofn.hInstance    = g_hResInst;
	ofn.lpstrFile    = strFileName;
	ofn.nMaxFile     = sizeof (strFileName);
	ofn.lpstrDefExt  = "trd";
	ofn.nFilterIndex = 1;
	ofn.lpstrFilter  = "Transformation data (*.trd)\0*.trd\0";
	ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_ENABLESIZING | OFN_NOREADONLYRETURN | OFN_OVERWRITEPROMPT;
	if (::GetSaveFileName (& ofn) == FALSE)
		return true;

	// Open the file.
	const CFileForWrite hFile (strFileName);
	if (! hFile.IsValid ()) {
		ErrorMsgBox ("Can't create file:\n %s", strFileName);
		return true;
	}

	// Save the file.
	CFileWriter fw (hFile);
	fw.WriteS (c_strTrdSignature, c_cTrdSignatureSize);
	for (size_t c = 0; c < _PtPairs.size (); ++ c) {
		if (_PtPairs [c].bDefined)
			fw.WriteFmt ("1\t%.5f\t%.5f\t%.5f\t%.5f\r\n", _PtPairs [c].ptFrom.x, _PtPairs [c].ptFrom.y, _PtPairs [c].ptTo.x, _PtPairs [c].ptTo.y);
		else
			fw.WriteS ("0\r\n");
	}
	fw.FlushBuffer ();

	return false;
}

bool LoadTransformDefFile (ptpairs_t & _PtPairs) {
	char strFileName [MAX_PATH + 1];
	strFileName [0] = '\0';

	// Ask file name.
	OPENFILENAME ofn;
	::ZeroMemory (& ofn, sizeof (OPENFILENAME));
	ofn.lStructSize  = sizeof (OPENFILENAME);
	ofn.hwndOwner    = g_hWnd;
	ofn.hInstance    = g_hResInst;
	ofn.lpstrFile    = strFileName;
	ofn.nMaxFile     = sizeof (strFileName);
	ofn.lpstrDefExt  = "trd";
	ofn.nFilterIndex = 1;
	ofn.lpstrFilter  = "Transformation data (*.trd)\0*.trd\0";
	ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_ENABLESIZING | OFN_HIDEREADONLY;
	if (::GetOpenFileName (& ofn) == FALSE)
		return true;

	// Open the file.
	const CFileForRead hFile (strFileName);
	if (! hFile.IsValid ()) {
		ErrorMsgBox ("Can't open file:\n %s", strFileName);
		return true;
	}

	// Load the file.
	const size_t cSize = ::GetFileSize (hFile, NULL);
	char * const pData = new char [cSize];
	CByteArrayHolder bah (reinterpret_cast<BYTE *> (pData));

	DWORD dwRead = 0;
	::ReadFile (hFile, pData, cSize, & dwRead, NULL);
	if (dwRead < cSize) {
		ErrorMsgBox ("Failed to read file: '%s'.", strFileName);
		return true;
	}
	
	// Validate.
	if (
		(
			cSize <= c_cTrdSignatureSize ||
			::memcmp (pData, c_strTrdSignature, c_cTrdSignatureSize) != 0
		) && (
			cSize <= c_cTrdSignatureSize_Old ||
			::memcmp (pData, c_strTrdSignature_Old, c_cTrdSignatureSize_Old) != 0
		)
	) {
		ErrorMsgBox ("Invalid format of file: '%s'.", strFileName);
		return true;
	}

	_PtPairs.clear ();

	const char * p = pData + c_cTrdSignatureSize;
	const char * const pEnd = pData + cSize;
	OmitSpaces (& p, pEnd);
	do {
		unsigned long ulValid = 0;
		ParseDecU (p, pEnd, & p, ulValid);

		_PtPairs.push_back (ptpair_t ());
		ptpair_t & pp = _PtPairs.back ();

		if (ulValid == 0) {
			pp.bDefined = false;
		} else {
			bool bOK = true;
			OmitSpaces (& p, pEnd);
			bOK = bOK && ParseReal (p, pEnd, & p, pp.ptFrom.x);
			OmitSpaces (& p, pEnd);
			bOK = bOK && ParseReal (p, pEnd, & p, pp.ptFrom.y);
			OmitSpaces (& p, pEnd);
			bOK = bOK && ParseReal (p, pEnd, & p, pp.ptTo.x);
			OmitSpaces (& p, pEnd);
			bOK = bOK && ParseReal (p, pEnd, & p, pp.ptTo.y);

			pp.bDefined = bOK;
		}

		OmitSpaces (& p, pEnd);
	} while (p < pEnd);

	const size_t cSize0 = _PtPairs.size ();
	if (cSize0 < 6) {
		_PtPairs.resize (6);
		for (size_t cPoint = cSize0; cPoint < _PtPairs.size (); ++ cPoint)
			_PtPairs [cPoint].bDefined = false;
	}

	return false;
}
